from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4.QtCore import QString
from PyQt4.QtCore import QTimer
from PyQt4.QtCore import SIGNAL
from PyQt4.QtCore import SLOT
from PyQt4.QtGui import QFileDialog
from deploy.constants import Config
from deploy.gui.autoLayout import AutoLayoutMixin
from deploy.gui.settingsDialog import SettingsDialog
from deploy.model.log import setLoggingLevel
from deploy.model.service import ServiceTableModel
import logging
import os

logger = logging.getLogger(__name__)

class MainWindow(QtGui.QMainWindow, AutoLayoutMixin):

    # For AutoLayoutMixin
    LAYOUT_FILE_NAME = 'layout.ui'

    REFRESH_TIMER_INTERVAL_MSEC = 1000

    def __init__(self):
        super(MainWindow, self).__init__()

        self.buildFile = None
        self.serviceTableModel = None
        self.selectedService = None

        self.loadUi()
        self._registerModels()
        self._connectSignals()
        self._setupRefreshTimer()

        self.actionToolVNC.setEnabled(False)
        self.actionServiceStart.setEnabled(False)
        self.actionServiceStop.setEnabled(False)

    def _registerModels(self):
        self.serviceTableModel = ServiceTableModel(self)
        self.servicesTable.setModel(self.serviceTableModel)

    def _connectSignals(self):
        # TODO: Need another object to be responsible for environment selection & related logic
        self.connect(self.actionEnvironmentLocal, QtCore.SIGNAL('triggered()'), self.localEnvironmentTriggered)
        self.connect(self.actionEnvironmentDevelopment, QtCore.SIGNAL('triggered()'), self.developmentEnvironmentTriggered)
        self.connect(self.actionEnvironmentStaging, QtCore.SIGNAL('triggered()'), self.stagingEnvironmentTriggered)
        self.connect(self.actionEnvironmentProduction, QtCore.SIGNAL('triggered()'), self.productionEnvironmentTriggered)

        # File Menu
        self.connect(self.actionFileSettings, SIGNAL('triggered()'), self.showSettingsDialog)
        self.connect(self.actionFileQuit, SIGNAL('triggered()'), QtGui.qApp, SLOT('quit()'))

        # Build Menu
        self.connect(self.actionSelectBuild, SIGNAL('triggered()'), self.selectBuild)

        # Service Table actions
        self.connect(self.servicesTable, SIGNAL('clicked(const QModelIndex&)'), self.serviceTableSelectionChanged)
        self.connect(self.serviceTableModel, SIGNAL('serviceStatusChanged(PyQt_PyObject)'), self.updateServiceControls)

        # Toolbar actions
        self.connect(self.actionServiceStart, SIGNAL('triggered()'), self.startSelectedService)
        self.connect(self.actionServiceStop, SIGNAL('triggered()'), self.stopSelectedService)


    def _setupRefreshTimer(self):
        '''Create and connect the refresh timer to various ui elements.'''
        timer = QTimer(self)
        self.connect(timer, SIGNAL('timeout()'), self.servicesTable.viewport(), SLOT('update()'))

        timer.start(self.REFRESH_TIMER_INTERVAL_MSEC)

    def serviceTableSelectionChanged(self, index):
        selectedService = self.serviceTableModel.getService(index)

        if selectedService != self.selectedService:
            self.selectedService = selectedService

        self.updateServiceControls(selectedService)

    def updateServiceControls(self, service):

        tools = {
            self.actionServiceStart : 'stopped',
            self.actionServiceStop : 'running'
        }

        for tool, enabledWhen in tools.iteritems():
            if service.status == enabledWhen:
                tool.setEnabled(True)
            else:
                tool.setEnabled(False)

    def selectBuild(self):
        '''Select the build for deploy operations.'''

        # TODO: It's going to get old recreating QFileDialogs like this all the time.
        #    This logic should be encapsulated somewhere, to make things a bit simpler to call
        filename = QFileDialog.getOpenFileName(self,
                                               QString('Select the build file'),
                                               QString(), #dir
                                               QString('*.zip'), #filter
                                               QString(), #selectedFilter
                                               QFileDialog.Options()) #options

        if not os.path.exists(filename):
            # TODO: What should be done here?
            return

        # TODO: This doesn't really seem like the best place to keep the file name...
        #    Probably a better place would be in a settings object
        self.buildFile = str(filename)
        self.buildLabel.setText(os.path.basename(self.buildFile))

    def showSettingsDialog(self):
        '''Show the settings dialog.'''
        settingsDialog = SettingsDialog(self)
        self.connect(settingsDialog, SIGNAL('settingChanged(QString)'), self.handleSettingChanged)
        settingsDialog.show()

    def handleSettingChanged(self, setting):
        logger.info('Setting change detected: %s' % setting)

        # Changes to the environment config may cause an update in the ServiceTableModel
        if str(setting) == Config.ENVIRONMENT_CONFIG_FILE:
            self.serviceTableModel.updateServices()
        elif str(setting) == Config.DEBUG_LEVEL:
            setLoggingLevel()

    def localEnvironmentTriggered(self):
        self._environmentTriggered('Local')

    def developmentEnvironmentTriggered(self):
        self._environmentTriggered('Development')

    def stagingEnvironmentTriggered(self):
        self._environmentTriggered('Staging')

    def productionEnvironmentTriggered(self):
        self._environmentTriggered('Production')

    def _environmentTriggered(self, environment):
        if environment != 'Local':
            self.actionEnvironmentLocal.setChecked(False)
        if environment != 'Development':
            self.actionEnvironmentDevelopment.setChecked(False)
        if environment != 'Staging':
            self.actionEnvironmentStaging.setChecked(False)
        if environment != 'Production':
            self.actionEnvironmentProduction.setChecked(False)

        self.environmentLabel.setText(environment)

    #
    # Service management
    #

    def startSelectedService(self):
        logger.info('Starting selected service.')
        service = self._getSelectedService()

        service.start()
        self.actionServiceStart.setEnabled(False)

    def stopSelectedService(self):
        logger.info('Stopping selected service.')
        service = self._getSelectedService()

        service.stop()
        self.actionServiceStop.setEnabled(False)

    def _getSelectedService(self):
        selectionModel = self.servicesTable.selectionModel()
        selectedRows = selectionModel.selectedRows()

        if not selectedRows or not selectedRows[0].isValid():
            return None

        selectedService = self.servicesTable.model().getService(selectedRows[0])
        return selectedService
